package com.live.shop.aliyun;

import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.live.shop.tool.GetUtil;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.UUID;
public class AliyunToken {
    private final static String TIME_ZONE = "GMT";
    private final static String FORMAT_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    private final static String URL_ENCODING = "UTF-8";
    private static final String ALGORITHM_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";

    //发送HTTP GET请求，获取token和有效期时间戳。
    public static JSONObject getTokenRequest(String accessKeyId,String accessKeySecret) {
        JSONObject tokenJsonObject = new JSONObject();
        // 所有请求参数
        Map<String, String> queryParamsMap = new HashMap<String, String>();
        queryParamsMap.put("AccessKeyId", accessKeyId);
        queryParamsMap.put("Action", "CreateToken");
        queryParamsMap.put("Version", "2019-02-28");
        queryParamsMap.put("Timestamp", getISO8601Time(null));
        queryParamsMap.put("Format", "JSON");
        queryParamsMap.put("RegionId", "cn-shanghai");
        queryParamsMap.put("SignatureMethod", "HMAC-SHA1");
        queryParamsMap.put("SignatureVersion", "1.0");
        queryParamsMap.put("SignatureNonce", getUniqueNonce());
        //1.构造规范化的请求字符串
        String queryString = canonicalizedQuery(queryParamsMap);
        if (null == queryString) {
            tokenJsonObject.put("code",0);
            tokenJsonObject.put("error","构造规范化的请求字符串失败！");
            return tokenJsonObject;
        }
        //2.构造签名字符串
        String method = "GET";  // 发送请求的 HTTP 方法，GET
        String urlPath = "/";   // 请求路径
        String stringToSign = createStringToSign(method, urlPath, queryString);
        if (null == stringToSign) {
            tokenJsonObject.put("code",0);
            tokenJsonObject.put("error","构造签名字符串失败！");
            return tokenJsonObject;
        }
        //3.计算签名
        String signature = sign(stringToSign, accessKeySecret + "&");
        if (null == signature) {
            tokenJsonObject.put("code",0);
            tokenJsonObject.put("error","计算签名失败！");
            return tokenJsonObject;
        }
        //4.将签名加入到第1步获取的请求字符串
        String queryStringWithSign = "Signature=" + signature + "&" + queryString;

        String url = "http://nls-meta.cn-shanghai.aliyuncs.com";
        url = url + "/";
        url = url + "?" + queryStringWithSign;
        Request request = new Request.Builder()
                .url(url)
                .header("Accept", "*/*")
                .get()
                .build();
        try {
            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            String result = response.body().string();
            if (response.isSuccessful()) {
                JSONObject rootObj = JSON.parseObject(result);
                JSONObject tokenObj = rootObj.getJSONObject("Token");
                if (tokenObj != null) {
                    String token = tokenObj.getString("Id");
                    long expireTime = tokenObj.getLongValue("ExpireTime");
                    tokenJsonObject.put("code",1);
                    tokenJsonObject.put("token",token);
                    tokenJsonObject.put("expireTime",expireTime);
                }else{
                    tokenJsonObject.put("code",0);
                    tokenJsonObject.put("error","获取Token失败 [响应成功]:" + rootObj.getString("Message"));
                    return tokenJsonObject;
                }
            }else {
                tokenJsonObject.put("code",0);
                tokenJsonObject.put("error","获取Token失败 [响应失败]:"+result);
                return tokenJsonObject;
            }
            response.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tokenJsonObject;
    }
    //获取时间戳  必须符合ISO8601规范，并需要使用UTC时间，时区为+0。
    private static String getISO8601Time(Date date) {
        Date nowDate = date;
        if (null == date) {
            nowDate = new Date();
        }
        SimpleDateFormat df = new SimpleDateFormat(FORMAT_ISO8601);
        df.setTimeZone(new SimpleTimeZone(0, TIME_ZONE));
        return df.format(nowDate);
    }
    //获取UUID
    private static String getUniqueNonce() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString();
    }
    //URL编码 使用UTF-8字符集按照RFC3986规则编码请求参数和参数取值。
    private static String percentEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, URL_ENCODING).replace("+", "%20")
                .replace("*", "%2A").replace("%7E", "~") : null;
    }
    //将参数排序后，进行规范化设置，组合成请求字符串。
    private static String canonicalizedQuery( Map<String, String> queryParamsMap) {
        String[] sortedKeys = queryParamsMap.keySet().toArray(new String[] {});
        Arrays.sort(sortedKeys);
        String queryString = null;
        try {
            StringBuilder canonicalizedQueryString = new StringBuilder();
            for (String key : sortedKeys) {
                canonicalizedQueryString.append("&")
                        .append(percentEncode(key)).append("=")
                        .append(percentEncode(queryParamsMap.get(key)));
            }
            queryString = canonicalizedQueryString.toString().substring(1);
        } catch (UnsupportedEncodingException e) {
             Log.d(GetUtil.TAG,"UTF-8 编码不支持.");
            e.printStackTrace();
        }
        return queryString;
    }
    //构造签名字符串
    private static String createStringToSign(String method, String urlPath, String queryString) {
        String stringToSign = null;
        try {
            StringBuilder strBuilderSign = new StringBuilder();
            strBuilderSign.append(method);
            strBuilderSign.append("&");
            strBuilderSign.append(percentEncode(urlPath));
            strBuilderSign.append("&");
            strBuilderSign.append(percentEncode(queryString));
            stringToSign = strBuilderSign.toString();
        } catch (UnsupportedEncodingException e) {
            Log.d(GetUtil.TAG,"UTF-8 编码不支持.");
            e.printStackTrace();
        }
        return stringToSign;
    }
    //计算签名
    private static String sign(String stringToSign, String accessKeySecret) {
        try {
            Mac mac = Mac.getInstance(ALGORITHM_NAME);
            mac.init(new SecretKeySpec(accessKeySecret.getBytes(ENCODING),ALGORITHM_NAME));
            byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING));
            String signBase64 = DatatypeConverter.printBase64Binary(signData);
            String signUrlEncode = percentEncode(signBase64);
            return signUrlEncode;
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException(e.toString());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException(e.toString());
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException(e.toString());
        }
    }
}